package com.ecoolex.chinadutyfree.retailer.core.manager;

import java.time.Instant;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.ecoolex.chinadutyfree.retailer.core.dao.GoodsProductDAO;
import com.ecoolex.chinadutyfree.retailer.entity.Goods;
import com.ecoolex.chinadutyfree.retailer.entity.GoodsProduct;
import com.ecoolex.chinadutyfree.retailer.entity.GoodsProduct.Column;
import com.ecoolex.chinadutyfree.retailer.entity.GoodsProductExample;
import com.ecoolex.chinadutyfree.retailer.enums.GoodsProductStatus;
import com.ecoolex.chinadutyfree.retailer.pojo.EditSpecDTO;
import com.ecoolex.chinadutyfree.retailer.pojo.EditSpecGroupDTO;
import com.ecoolex.framework.common.enums.ResultCode;
import com.ecoolex.framework.common.util.BizAssert;
import com.ecoolex.framework.common.util.Check;
import com.ecoolex.framework.common.util.CollectorUtil;
import com.ecoolex.framework.common.util.Ternary;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;


@Service
public class GoodsProductManager {

    @Autowired
    private GoodsProductDAO dao;

    @Autowired
    private GoodsBarcodeManager goodsBarcodeManager;

    @Autowired
    private DirectMailGoodsProductManager directMailGoodsProductManager;

    @Autowired
    private DirectMailGoodsShoppingCartManager directMailGoodsShoppingCartManager;

    public void update(Goods goods, List<EditSpecGroupDTO> specGroup, String updateUser) {
        // 迭代出所有可能
        Set<List<EditSpecDTO>> result = Sets.newLinkedHashSet();
        forEachAllResult(result, specGroup, 0, Lists.newArrayList());
        
        BizAssert.isTrue(result.size() <= 1000, "规格组合必须小于等于1000种组合");

        // 旧的产品
        List<GoodsProduct> oldList = queryByGoodsId(goods.getGoodsId());

        Iterator<List<EditSpecDTO>> iterator = result.iterator();
        for (int i = 0; iterator.hasNext(); i++) {
            List<EditSpecDTO> specList = iterator.next();

            // 根据规格排序
            String specIds = Arrays.toString(
                specList.stream().map(EditSpecDTO::getSpecId).sorted(Integer::compareTo).toArray(Integer[]::new));
            String specNames = Arrays.toString(specList.stream().map(EditSpecDTO::getName).toArray(String[]::new));

            GoodsProduct product = oldList.stream().collect(CollectorUtil.first(p -> p.getSpecIds().equals(specIds)));

            if (Check.notNull(product)) {
                product.setSpecNames(specNames);
                product.setSpecSorting(i + 1);
                product.setUpdateUser(updateUser);
                product.setUpdateTime(Date.from(Instant.now()));
                dao.updateByPrimaryKeySelective(product,
                    Column.specNames,
                    Column.specSorting,
                    Column.updateUser,
                    Column.updateTime);
                // 修改直邮商品产品的信息
                directMailGoodsProductManager.updateProductInfo(product, updateUser);
                // 修改直邮商品购物车的信息
                directMailGoodsShoppingCartManager.updateProductInfo(product, updateUser);
                // 移除已经存在的
                oldList.remove(product);
            } else {
                product = new GoodsProduct();
                product.setGoodsId(goods.getGoodsId());
                product.setSpecIds(specIds);
                product.setSpecNames(specNames);
                product.setSpecSorting(i + 1);
                product.setStockNumber(0);
                product.setUsedStockNumber(0);
                product.setSoldNumber(0);
                product.setStatus(GoodsProductStatus.NORMAL.real());
                product.setDeleted(GoodsProduct.NOT_DELETED);
                product.setCreateUser(updateUser);
                product.setCreateTime(Date.from(Instant.now()));
                product.setUpdateUser(updateUser);
                product.setUpdateTime(Date.from(Instant.now()));

                dao.insert(product);
            }
        }

        // 2020-03-04 暂行不能删除规格值, 只能添加或者编辑
//        BizAssert.isTrue(Check.isNullOrEmpty(oldList), "规格值不能进行删除操作");
        // 删除多余的
        oldList.forEach(old -> delete(old, updateUser));

    }

    private void delete(GoodsProduct product, String updateUser) {
        product.setDeleted(GoodsProduct.IS_DELETED);
        product.setUpdateUser(updateUser);
        product.setUpdateTime(Date.from(Instant.now()));

        dao.updateByPrimaryKeySelective(product, Column.deleted, Column.updateUser, Column.updateTime);

        // 删除产品条码
        goodsBarcodeManager.deleteByProductId(product.getProductId(), updateUser);
        // 删除关联的直邮商品的产品
        directMailGoodsProductManager.deleteProduct(product, updateUser);
        // 作废购物车中的商品
        directMailGoodsShoppingCartManager.invalidByProductId(product.getProductId(), updateUser);
    }

    public void deleteByGoodsId(Integer goodsId, String updateUser) {
        List<GoodsProduct> productList = queryByGoodsId(goodsId);
        productList.forEach(product -> delete(product, updateUser));
    }

    public GoodsProduct geyByGoodsIdAndSpecIds(Integer goodsId, String specIds) {
        GoodsProductExample example = new GoodsProductExample();
        example.createCriteria().andGoodsIdEqualTo(goodsId).andSpecIdsEqualTo(specIds).andDeletedEqualTo(
            GoodsProduct.NOT_DELETED);
        return dao.selectOneByExample(example);
    }

    public List<GoodsProduct> queryByGoodsId(Integer goodsId) {
        GoodsProductExample example = new GoodsProductExample();
        example.createCriteria().andGoodsIdEqualTo(goodsId).andDeletedEqualTo(GoodsProduct.NOT_DELETED);
        example.orderBy(Column.specSorting.asc());
        return dao.selectByExample(example);
    }

    public GoodsProduct getById(Integer productId) {
        return dao.selectByPrimaryKeyWithLogicalDelete(productId, GoodsProduct.NOT_DELETED);
    }

    @Transactional
    public GoodsProduct update(GoodsProduct product, List<String> barcodeList, String updateUser) {
        product.setUpdateUser(updateUser);
        product.setUpdateTime(Date.from(Instant.now()));

        GoodsProductExample example = new GoodsProductExample();

        example.createCriteria().andProductIdEqualTo(product.getProductId())
            // 必须大于等于已经使用的库存数量, 否则修改失败
            .andUsedStockNumberLessThanOrEqualTo(product.getStockNumber()).andDeletedEqualTo(GoodsProduct.NOT_DELETED);
        int row = dao.updateByExampleSelective(product,
            example,
            Column.excludes(Column.goodsId,
                Column.specIds,
                Column.specNames,
                Column.specSorting,
                Column.usedStockNumber,
                Column.soldNumber,
                Column.status,
                Column.deleted,
                Column.createUser,
                Column.createTime));
        BizAssert.isTrue(row == 1, ResultCode.BIZ.build(1), "更新失败,库存必须大于等于已使用库存");
        // 产品条码
        goodsBarcodeManager.update(product, barcodeList, updateUser);
        return product;
    }

    public boolean resetUsedStockNumber(GoodsProduct product, String updateUser) {
        return dao.resetUsedStockNumber(product.getProductId(), updateUser) > 0;
    }

    public boolean addSoldNumber(Integer goodsProductId, Integer buyNumber, String updateUser) {
        return dao.addSoldNumber(goodsProductId, buyNumber, updateUser) == 1;
    }

    private void forEachAllResult(final Set<List<EditSpecDTO>> result, List<EditSpecGroupDTO> specGroup, int index, List<EditSpecDTO> specList) {
        EditSpecGroupDTO group = specGroup.get(index);

        boolean flag = index < specGroup.size() - 1;
        group.getSpecList().forEach(spec -> {
            List<EditSpecDTO> newSpecList = Lists.newArrayList(specList);
            newSpecList.add(spec);
            if (flag) {
                forEachAllResult(result, specGroup, (index + 1), newSpecList);
            } else {
                result.add(newSpecList);
            }
        });
    }

    public Long sumStockNumberByGoodsId(Integer goodsId) {
        GoodsProductExample example = new GoodsProductExample();
        example.createCriteria().andGoodsIdEqualTo(goodsId).andDeletedEqualTo(GoodsProduct.NOT_DELETED);
        Long result = dao.sumStockNumberByExample(example);
        return Ternary.notNull(result, 0L);
    }

    public Long sumUsedStockNumberByGoodsId(Integer goodsId) {
        GoodsProductExample example = new GoodsProductExample();
        example.createCriteria().andGoodsIdEqualTo(goodsId).andDeletedEqualTo(GoodsProduct.NOT_DELETED);
        Long result = dao.sumUsedStockNumberByExample(example);
        return Ternary.notNull(result, 0L);
    }

    public Long sumSoldNumberByGoodsId(Integer goodsId) {
        GoodsProductExample example = new GoodsProductExample();
        example.createCriteria().andGoodsIdEqualTo(goodsId).andDeletedEqualTo(GoodsProduct.NOT_DELETED);
        Long result = dao.sumSoldNumberByExample(example);
        return Ternary.notNull(result, 0L);
    }
}